﻿using CLM.Gestao.Administrador.BLL;
using CLM.Gestao.Custos.BLL;
using CLM.Gestao.Despesas.BLL;
using CLM.Gestao.Vendas.BLL;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CLM.Gestao.Relatorios.BLL
{
    /// <summary>
    /// 
    /// </summary>

    public class Relatorio
    {
        #region Consultas

        #region Relatório PNL de Vendas

        /// <summary>
        /// Relatório PNL de Vendas
        /// </summary>
        /// <param name="pIdPeriodo">Período a ser gerado o relatório</param>
        /// <returns>Lista</returns>
        public List<ListaVendas> GerarRelatorioPNLVendas(int[] pIdPeriodo)
        {
            // Dictionary de Indicadores de Vendas para recuperar o ID, utilizando o nome
            IndicadorVenda Indicador = new IndicadorVenda();
            var IndicadoresVendas = Indicador.GetLista().ToDictionary(d => d.NomeIndicadorVenda);

            // Dictionary de tipos de lançamento para recuperar o ID, utilizando o nome
            LancamentoTipo LancamentoTipo = new LancamentoTipo();
            var LancamentosTipos = LancamentoTipo.GetLista().ToDictionary(d => d.DescricaoLancamentoTipo);

            List<ListaVendas> Lista = new List<ListaVendas>();
            CLM.Gestao.Vendas.BLL.Lancamento Lancamento = new CLM.Gestao.Vendas.BLL.Lancamento();
            LancamentoVenda LancamentoVenda = new LancamentoVenda();

            Lista = (from l in Lancamento.GetLista(new Vendas.BLL.Lancamento.Lista() { IdLancamentoTipo = LancamentosTipos["Real"].IdLancamentoTipo }).Where(w => pIdPeriodo.Contains((int)w.IdPeriodo)).Select(s => s) // IdLancamentoTipo = "Real"
                     group l by new
                     {
                         CodigoGlobal = l.CodigoProdutoGlobal,
                         NomeGlobal = l.NomeProdutoGlobal,
                         NomeFamilia = l.NomeProdutoFamilia
                     }
                         into gr
                         select new ListaVendas()
                        {
                            CodigoProdutoGlobal = gr.Key.CodigoGlobal,
                            NomeProdutoGlobal = gr.Key.NomeGlobal,
                            NomeProdutoFamilia = gr.Key.NomeFamilia,
                            Volumes = Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.GSalesBrU].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)), // GSales b.r. (u)
                            ReturnsUnit = Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.ReturnsU].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)), // Returns (u)
                            VolumeAfterReturns =
                                Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.GSalesBrU].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)
                                + gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.ReturnsU].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)), // GSales b.r. (u) + Returns (u)
                            GrossSales = Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.GSalesBrV].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)), // GSales b.r. (V)
                            ReturnAmount = Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.ReturnsV].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)), // Returns (V)
                            TotalOthersRevenue = null,
                            OthersRevenue = null,
                            GrossProceedOfSales =
                                Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.GSalesBrV].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)
                                + gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.ReturnsV].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)), // GSales b.r. (V) + Returns (V)
                            TotalGeneralPriceReduction = Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.OthCredRebV].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)), // Oth.Cred/Reb. (V)
                            NetProceedsOfSales =
                                Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.OthCredRebV].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)
                                + (gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.GSalesBrV].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)
                                + gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.ReturnsV].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento))), // Oth.Cred/Reb. (V) + (GSales b.r. (V) + Returns (V))
                            TotalPerfTrade = Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.TradeAllowances].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)), // Trade Allowances
                            CashDiscount = null,
                            NetSales = Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.NetSales].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)), // Net Sales
                            ListPrice = null,
                            VolumesAfterReturn = null,
                            NetNetSales =
                                Math.Round(gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.NetSales].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)
                                + gr.Where(w => w.IdIndicadorVenda == IndicadoresVendas[Indicadores.IndicadoresVendas.TradeAllowances].IdIndicadorVenda).Sum(s => (double)s.ValorLancamento)) // Net Sales + Trade Allowances
                        }).ToList();

            return Lista;
        }

        #endregion Relatório PNL de Vendas

        #region Relatório PNL de Custos e Despesas

        /// <summary>
        /// Relatório PNL de Custos e Despesas
        /// </summary>
        /// <param name="pIdPeriodo">Período a ser gerado o relatório</param>
        /// <returns>Lista</returns>
        public List<ListaDespesasCustos> GerarRelatorioPNLCustosDespesas(int[] pIdPeriodo)
        {
            // Dictionary de Indicadores de Desdpesas para recuperar o ID, utilizando o nome
            IndicadorDespesa IndicadorDespesa = new IndicadorDespesa();
            var IndicadoresDespesas = IndicadorDespesa.GetLista().ToDictionary(d => d.NomeIndicadorDespesa);

            // Dictionary de Indicadores de Desdpesas para recuperar o ID, utilizando o nome
            IndicadorCusto IndicadorCusto = new IndicadorCusto();
            var IndicadoresCustos = IndicadorCusto.GetLista().ToDictionary(d => d.NomeIndicadorCusto);

            // Dictionary de tipos de lançamento para recuperar o ID, utilizando o nome
            LancamentoTipo LancamentoTipo = new LancamentoTipo();
            var TiposLancamento = LancamentoTipo.GetLista().ToDictionary(d => d.DescricaoLancamentoTipo);


            CentroCusto.Lista c = new CentroCusto.Lista();

            

            List<ListaDespesasCustos> Lista = new List<ListaDespesasCustos>();

            CLM.Gestao.Custos.BLL.Lancamento LancamentoC = new CLM.Gestao.Custos.BLL.Lancamento();
            LancamentoCusto LancamentoCusto = new Custos.BLL.LancamentoCusto();

            CLM.Gestao.Despesas.BLL.Lancamento LancamentoD = new CLM.Gestao.Despesas.BLL.Lancamento();
            LancamentoDespesa LancamentoDespesa = new Despesas.BLL.LancamentoDespesa();

            Lista = (from l in LancamentoC.GetListaPNL(new Custos.BLL.Lancamento.Lista() { IdLancamentoTipo = TiposLancamento["Real"].IdLancamentoTipo }).Where(w => pIdPeriodo.Contains((int)w.IdPeriodo)).Select(s => s) // IdLancamentoTipo = "Real"
                     //join v in LancamentoCusto.GetLista()
                     //on l.IdLancamento equals v.IdLancamento
                     group l by new
                     {
                         NomeFamilia = l.NomeProdutoFamilia
                     }
                         into gr
                         select new ListaDespesasCustos()
                         {
                             NomeProdutoFamilia = gr.Key.NomeFamilia,
                             StandardCosts = gr.Where(w => w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.StandardCosts].IdIndicadorCusto).Sum(s => (double)s.ValorLancamento),
                             StandardCOGS = gr.Where(w => w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.StandardCOGS].IdIndicadorCusto).Sum(s => (double)s.ValorLancamento),
                             PPVThirdParty = gr.Where(w => (w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.NominalPPVCompras].IdIndicadorCusto
                                                                || w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.NominalPPVOrdemProducao].IdIndicadorCusto)).Sum(s => (double)s.ValorLancamento),
                             InventoryAdjustments = gr.Where(w => ((w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.BadGoodsAllowances].IdIndicadorCusto && w.IdPeriodo == pIdPeriodo[0])
                                                                || w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.BadGoodsExpenses].IdIndicadorCusto)).Sum(s => (double)s.ValorLancamento),
                             FreightCustom = gr.Where(w => (w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.ImportDuties].IdIndicadorCusto
                                                         || w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.InboundFreightInsurance].IdIndicadorCusto)).Sum(s => (double)s.ValorLancamento),
                             OtherCOGS = gr.Where(w => (w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.TaxOverThirdParty].IdIndicadorCusto
                                                     || w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.LocalQARework].IdIndicadorCusto
                                                     || w.IdIndicadorCusto == IndicadoresCustos[Indicadores.IndicadoresCustos.OtherCostsUndefined].IdIndicadorCusto)).Sum(s => (double)s.ValorLancamento)
                         }).Union((
                    from l in LancamentoD.GetLista(new Despesas.BLL.Lancamento.Lista() { IdLancamentoTipo = TiposLancamento["Real"].IdLancamentoTipo }).Where(w => pIdPeriodo.Contains((int)w.IdPeriodo)).Select(s => s) // IdLancamentoTipo = "Real"
                    //join v in LancamentoDespesa.GetLista()
                    //on l.IdLancamento equals v.IdLancamento
                    group l by new
                    {
                        NomeFamilia = l.NomeProdutoFamilia
                    }
                        into gr
                        select new ListaDespesasCustos()
                        {
                            NomeProdutoFamilia = gr.Key.NomeFamilia,
                            VariableMarketing = gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.VariableMarketing].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento),
                            DirectSelling = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.DirectSelling].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            FixedMarketing = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.FixedMarketing].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            Warehouse = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.Warehouse].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            ITCosts = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.ITCosts].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            FinanceCosts = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.FinanceCosts].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            HRCosts = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.HRCosts].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            LegalManagement = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.LegalManagement].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            OtherGA = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.OtherGA].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            BadDebts = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.BadDebts].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            Other = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.Other].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            RegulatoryAffairs = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.RegulatoryAffairs].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento)),
                            MedicalAffairs = Math.Round(gr.Where(w => w.IdIndicadorDespesa == IndicadoresDespesas[Indicadores.IndicadoresDespesas.MedicalAffairs].IdIndicadorDespesa).Sum(s => (double)s.ValorLancamento))
                        }))
                        .GroupBy(g => g.NomeProdutoFamilia).Select(s => new ListaDespesasCustos
                        {
                            NomeProdutoFamilia = s.Key,
                            StandardCosts = s.Sum(sm => sm.StandardCosts),
                            StandardCOGS = s.Sum(sm => sm.StandardCOGS),
                            PPVThirdParty = s.Sum(sm => sm.PPVThirdParty),
                            InventoryAdjustments = s.Sum(sm => sm.InventoryAdjustments),
                            FreightCustom = s.Sum(sm => sm.FreightCustom),
                            OtherCOGS = s.Sum(sm => sm.OtherCOGS),
                            VariableMarketing = s.Sum(sm => sm.VariableMarketing),
                            DirectSelling = s.Sum(sm => sm.DirectSelling),
                            FixedMarketing = s.Sum(sm => sm.FixedMarketing),
                            Warehouse = s.Sum(sm => sm.Warehouse),
                            ITCosts = s.Sum(sm => sm.ITCosts),
                            FinanceCosts = s.Sum(sm => sm.FinanceCosts),
                            HRCosts = s.Sum(sm => sm.HRCosts),
                            LegalManagement = s.Sum(sm => sm.LegalManagement),
                            OtherGA = s.Sum(sm => sm.OtherGA),
                            BadDebts = s.Sum(sm => sm.BadDebts),
                            Other = s.Sum(sm => sm.Other),
                            RegulatoryAffairs = s.Sum(sm => sm.RegulatoryAffairs),
                            MedicalAffairs = s.Sum(sm => sm.MedicalAffairs)
                        }).ToList();

            return Lista;
        }

        #endregion Relatório PNL de Custos e Despesas

        #endregion Consultas

        #region Classes

        /// <summary>
        /// 
        /// </summary>
        public class ListaVendas
        {
            public string CodigoProdutoGlobal { get; set; }
            public string NomeProdutoGlobal { get; set; }
            public string NomeProdutoFamilia { get; set; }
            public double? Volumes { get; set; } // GSales b.r. (u)
            public double? ReturnsUnit { get; set; } // Returns (u)
            public double? VolumeAfterReturns { get; set; } // GSales b.r. (u) + Returns (u)
            public double? GrossSales { get; set; } // GSales b.r. (V)
            public double? ReturnAmount { get; set; } // Returns (V)
            public double? TotalOthersRevenue { get; set; } // null
            public double? OthersRevenue { get; set; } // null
            public double? GrossProceedOfSales { get; set; } // GSales b.r. (V) + Returns (V)
            public double? TotalGeneralPriceReduction { get; set; } //Oth.Cred/Reb. (V)
            public double? NetProceedsOfSales { get; set; } // Oth.Cred/Reb. (V) + (GSales b.r. (V) + Returns (V))
            public double? TotalPerfTrade { get; set; } // Trade Allowances
            public double? CashDiscount { get; set; } // null
            public double? NetSales { get; set; } // Net Sales
            public double? ListPrice { get; set; } // null
            public double? VolumesAfterReturn { get; set; } // null
            public double? NetNetSales { get; set; } // Net Sales + Trade Allowances
        }

        /// <summary>
        /// 
        /// </summary>
        public class ListaDespesasCustos
        {
            public string NomeProdutoFamilia { get; set; }
            public double? StandardCosts { get; set; }
            public double? StandardCOGS { get; set; }
            public double? PPVIG { get; set; }
            public double? PPVThirdParty { get; set; }
            public double? InventoryAdjustments { get; set; }
            public double? FreightCustom { get; set; }
            public double? OtherCOGS { get; set; }
            public double? ThirdParty { get; set; }
            public double? LOREALRoyalties { get; set; }
            public double? VariableMarketing { get; set; }
            public double? DirectSelling { get; set; }
            public double? Commission { get; set; }
            public double? FixedMarketing { get; set; }
            public double? Warehouse { get; set; }
            public double? ITCosts { get; set; }
            public double? FinanceCosts { get; set; }
            public double? HRCosts { get; set; }
            public double? LegalManagement { get; set; }
            public double? OtherGA { get; set; }
            public double? BadDebts { get; set; }
            public double? Other { get; set; }
            public double? RegulatoryAffairs { get; set; }
            public double? MedicalAffairs { get; set; }
        }

        #endregion Classes
    }
}